#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>

#if defined (linux)

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close (s)

    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
    typedef struct in_addr IN_ADDR;

#elif defined (WIN32)

    #include <winsock2.h>

    #define SIGQUIT SIGBREAK
    typedef int socklen_t;

#else

    #error not defined

#endif

#include "network.h"
#include "database.h"
#include "request.h"

#define BUF_SIZE 2048

void error (char *msg) {
	perror(msg);
	exit(EXIT_FAILURE);
}

void s_write (int sockfd, char *msg) {
	int n;
	n = send (sockfd, msg, strlen(msg), 0);
	if (n == -1)
		error ("ERROR writing to socket");
}

int s_read (int sockfd, char *buffer) {
	memset(buffer, 0, BUF_SIZE);
	errno = 0;
	int n = recv (sockfd, buffer, BUF_SIZE, 0);
	if (n == 0) return -1;
	if (n == -1) error("ERROR reading from socket");
	return n;
}

int create_tcp_socket (int portno) {
	int sockfd;
	struct sockaddr_in serv_addr;
	sockfd = socket(AF_INET, SOCK_STREAM, 0); 					/* AF_INET : IPv4 Internet protocols,
											SOCK_STREAM : rovides sequenced, reliable, two-way, connection-based byte  streams.
											0 : socket protocol */
	if (sockfd < 0)
		error ("ERROR opening socket");
	memset((char *) &serv_addr, 0, sizeof(serv_addr));					/* bzero - write zero-valued bytes */
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;						/* Can be assigned to any local address */
	serv_addr.sin_port = htons(portno);						/* Convert values between host and network byte order */
	if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)	// assigns the address specified to the socket
		error("ERROR on binding");

	return sockfd;
}

struct ip_and_socket accept_client (int sockfd) {
	int newsockfd;
	struct sockaddr_in cli_addr;
	socklen_t sinsize = sizeof(struct sockaddr_in);					// Size of the address specification structure.
	newsockfd = accept (sockfd, (struct sockaddr*) &cli_addr, &sinsize);		// accept a connection on a socket, on success returns the incomming socket

	struct ip_and_socket ias;
	ias.sockfd = newsockfd;
	ias.ip = inet_ntoa(cli_addr.sin_addr);

	if (newsockfd < 0)
		error("ERROR on accept");
	return ias;
}

